package net.jxta.myjxta.plugins.example;

import net.jxta.myjxta.plugin.*;
import net.jxta.myjxta.presence.PeerStatus;
import net.jxta.myjxta.presence.PresenceController;
import net.jxta.myjxta.ui.action.PeerPingAction;
import net.jxta.myjxta.util.Group;
import net.jxta.myjxta.util.Logging;
import net.jxta.myjxta.util.Resources;
import net.jxta.myjxta.util.objectmodel.JxtaNode;
import net.jxta.myjxta.util.objectmodel.PeerNode;

import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.logging.Logger;

/**
 * Example Plugin that sends a ping command to every known peer if the user
 * stats or stops the plugin (via the plugin menu entry).
 * If the user starts the plugin an "online" state will be transmitted via the
 * ping command, if the user stops the plugin an "away" state will be transmitted
 * <p/>
 * Additionally an "offline" state will be send to each known peer
 * if the user resigns from a joined group
 * <p/>
 * This code is only an example of the plugin interface - it was not the
 * intention of the author to implement a very clever implementation of the
 * typical p2p presence problem....
 */
public final class SimpleRosterPlugin extends PluginBase implements Plugin, IPluginNotificationHandler, PluginContainer.IPopupProvider {

    private static final Logger LOG = Logger.getLogger(SimpleRosterPlugin.class.getName());

    //the plugin maintains a list of joined groups (via groupJoined(...)) 
    private final ArrayList<Group> m_joinedGroups = new ArrayList<Group>();


    public SimpleRosterPlugin() {
        super();
    }

    public void init(PluginContainer c) {
        super.init(c);
        start();  // you can activate a plugin inside the init method
    }

    public void start() {
        super.start();
        for (Group group : m_joinedGroups) {
            setOnlineStateForGroup(group);
            resendOwnStatus(group);
        }
        m_container.registerPopupProvider(this);
    }

    public void popupRequested(PluginContainer.IPopupGenerator popupGenerator, ISelectableNode[] selectedNodes, MouseEvent triggerEvent) {
        if (!isRunning())
            return;

        if (selectedNodes != null && selectedNodes.length >= 1) {
            JxtaNode jxtaNode = selectedNodes[0].getJxtaNode();
            if (jxtaNode instanceof PeerNode) {
                PluginContainer.MenuPath peerPath = new PluginContainer.MenuPath(Resources.getStrings().getString("menu.peer"), KeyEvent.VK_P);
                popupGenerator.addPopup(new PluginContainer.MenuPath[]{peerPath}, 9, new PeerPingAction("Ping", m_container.getMyJxta().getView()));
            }
        }
    }

    public void stop() {
        LOG.log(Logging.STATUS_LEVEL, "SimpleRosterPlugin stopped");
        for (Group group : m_joinedGroups) {
            PresenceController.setOwnPeerStatus(group, PeerStatus.getAwayState("signoff notifier disabled"));
            resendOwnStatus(group);
        }
        m_container.removePopupProvider(this);
        super.stop();
    }

    public void destroy() {

        if (m_running) {
            stop();
        }
        super.destroy();
    }

    public String getName() {
        return "Signoff Notifier (SimpleRoster)";
    }

    // END OF PLUGIN API

    // HELPER METHODS

    private void setOnlineStateForGroup(Group p_group) {
        LOG.log(java.util.logging.Level.INFO,
                "setting online state for group" + p_group);
        PresenceController.setOwnPeerStatus(p_group, PeerStatus.getOnlineState("signoff notifier enabled"));
    }

    private void resendOwnStatus(Group p_group) {
        LOG.log(java.util.logging.Level.INFO, "sending ping for:" + p_group);
        PresenceController.pingAllNodesInGroup(p_group);
    }

    public IPluginNotificationHandler getPluginNotificationHander() {
        return this;  //for now we will implement this interface ourselve, 
        //the plugin will grow so this will be moved into a separate class
    }


    //this method is called by myjxta every time a group is joined
    public void groupJoined(Group p_group) {
        if (!p_group.isVisible())
            return;

        m_joinedGroups.add(p_group);

        if (isRunning()) {
            setOnlineStateForGroup(p_group);
        }
    }

    public void groupResigned(Group p_group) {
        if (!p_group.isVisible())
            return;

        m_joinedGroups.remove(p_group);
        if (isRunning()) {

            //user has left the group... send the notification to inform others...
            fireResignListenerForGroup(p_group);
            try {
                Thread.sleep(500); //hack! WARNING, THIS WILL BLOCK THE SWING THREAD FOR 500ms, dont increase the value!
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    private void fireResignListenerForGroup(Group p_group) {
        LOG.log(java.util.logging.Level.INFO, "sending ping for:" + p_group);

        //first set our own state to offline for this group
        PresenceController.setOwnPeerStatus(p_group, PeerStatus.getOfflineState("signed off"));

        //now send a general status ping to all (known) peers in the group
        //thats inefficient.. we should use a propagation pipe broadcast for this, but its
        //only an example....
        PresenceController.pingAllNodesInGroup(p_group);
    }


    public void groupStateChanged(Group p_group) {
        //nothing so far
    }
}
